#!/bin/sh

export PATH="/usr/sbin:/usr/bin:/sbin:/bin"

# set colors if supported
if [ -t 0 ];then
    C_BLACK='\e[1;30m'
    C_RED='\e[1;31m'
    C_GREEN='\e[1;32m'
    C_YELLOW='\e[1;33m'
    C_BLUE='\e[1;34m'
    C_PURPLE='\e[1;35m'
    C_CYAN='\e[1;36m'
    C_WHITE='\e[1;37m'
    C_CLEAR='\e[m'
fi

# usefull functions
msg() {
    echo -e " ${C_BLUE}*${C_CLEAR} ${@}"
}

error() {
    echo -e " ${C_RED}*${C_CLEAR} ${@}"
}

rescue_shell() {
    msg "Running rescue Shell..."
    /bin/sh
}

cmd() {
    ${@}
    [ "$?" != "0" ] && rescue_shell
}

msg "Mounting pseudo filesystems..."
cmd mkdir -p /proc /sys /dev /run /newroot
cmd mount -t proc proc /proc -o nosuid,noexec,nodev
cmd mount -t sysfs sys /sys -o nosuid,noexec,nodev
cmd mount -t devtmpfs dev /dev -o mode=0755,nosuid

if [ ! -e "/etc/mtab" ];then
    msg "Creating mtab symlink..."
    ln -s /proc/mounts /etc/mtab
fi

msg "Parsing cmdline options..."
# find will complain otherwise
mkdir -p /hooks
hooks="$(find /hooks ! -type d ! -name 'late_*' | sort)"
latehooks="$(find /hooks ! -type d -name 'late_*' | sort)"
init="/sbin/init"
root=""
state="ro"
for arg in $(cat /proc/cmdline);do
    case "$arg" in
        hooks=*) hooks="${arg#*=}"
                 # spaces in kernel arguments are not allowed
                 hooks="${hooks//,/ }" ;;
        latehooks=*) latehooks="${arg#*=}"
                 # spaces in kernel arguments are not allowed
                 latehooks="${latehooks//,/ }" ;;
        init=*) init="${arg#*=}" ;;
        root=*) root="${arg#*=}" ;;
        ro|rw) state="${arg}" ;;
        shell) rescue_shell ;;
    esac
done

for hook in $hooks;do
    # done only because of the latehooks
    base="$(basename "$hook")"
    if [ -f "/hooks/$base" ];then
        msg "Sourcing hook: $base"
        cmd . "/hooks/$base"
    else
        error "Missing hook: $base"
    fi
done

case "$root" in
      /dev/*) device="$root" ;;
      UUID=*) device="/dev/disk/by-uuid/${root#*=}"  ;;
      LABEL=*) device="/dev/disk/by-label/${root#*=}" ;;
esac

case "$(cat /proc/sys/kernel/hotplug)" in
    # could be /usr/bin, /sbin, etc.
    */mdev)
        # oh, boy! mdev does not support device UUID/LABEL thus /dev/disk/by-*
        # can not be used but Busybox's blkid applet does not support -U and
        # -L either so the code bellow requires blkid from util-linux, best
        # effort made..
        case "$root" in
            UUID=*) device="$(blkid -U "${root#*=}")"  ;;
            LABEL=*) device="$(blkid -L "${root#*=}")" ;;
        esac
    ;;
esac

# device is optional, a hook may take care of the root (e.g. on Live CD)
if [ -e "$device" ];then
    msg "Checking the root device..."
    cmd fsck -M -T "$device"
    msg "Mounting the root filesystem..."
    cmd mount -o "$state" "$device" /newroot
fi

for hook in $latehooks;do
    # done only because of the latehooks
    base="$(basename "$hook")"
    if [ -f "/hooks/$base" ];then
        msg "Sourcing late hook: $base"
        cmd . "/hooks/$base"
    else
        error "Missing late hook: $base"
    fi
done

# a hook could have mounted root
if [ -e "/newroot/$init" ];then
    msg "Moving pseudo-filesystems..."
    cmd mount --move /dev /newroot/dev

    msg "Switching root..."
    cmd exec switch_root /newroot "$init" "$@"
else
    msg "Root filesystem invalid..."
    exec /bin/sh
fi
